package br.com.saeng2D.objeto.linha;

import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.io.PrintWriter;

import br.com.saeng2D.objeto.AbstratoObjeto;
import br.com.saeng2D.objeto.forca.ForcaCentralizada2;
import br.com.saeng2D.objeto.forca_d.Reta;
import br.com.saeng2D.objeto.ponto.Ponto;
import br.com.saeng2D.util.Constantes;
import br.com.saeng2D.util.P2D;
import br.com.saeng2D.util.R2D;
import br.com.saeng2D.util.Util;
import br.com.saeng2D.util.Vetor;

public class Linha extends AbstratoObjeto {
	public static final int ALCANCE_CLICK_LINHA = Util
			.getInt("alcance_click_linha");
	private Ponto ponto1;
	private Ponto ponto2;

	//-------------------------------------
	//ATRIBUTOS DE UMA LINHA QUANDO PLOTADA
	//-------------------------------------
	private boolean ehLinhaMedidaParalela;
	private X x1;
	private X x2;	
	private String rotulo;
	private int xRotulo;
	private int yRotulo;
	private Ponto pontoCentral;
//	private SetaDinamica setaDinamica;
//	private ForcaCentralizada forcaCentralizada;
	private ForcaCentralizada2 forcaCentralizada2;
	private double grauInclinacao;
	
	public Linha(Ponto ponto1, Ponto ponto2) {
		super(null, "Linha", 0, 0, 0, 0);
		this.ponto1 = ponto1;
		this.ponto2 = ponto2;
		if (ponto1 == null || ponto2 == null) {
			throw new RuntimeException("Linha -> Ponto(s) nulo.");
		}
		corFundo = Util.getCor("cor_linha");
	}

	public AbstratoObjeto prototipo() {
		Linha linha = new Linha((Ponto) ponto1.prototipo(), (Ponto) ponto2.prototipo());
		if(pontoCentral != null) {
			Ponto ponto = (Ponto) pontoCentral.prototipo();
			ponto.setPreenchido(pontoCentral.isPreenchido());
			ponto.setCorFundo(pontoCentral.getCorFundo());
			linha.setPontoCentral(ponto);
		}
		return linha;
	}

	public Linha getLinhaMedidaParalela() {
		int distancia = Util.getInt("distancia_linha_medida_paralela");
		Vetor vetor = criarVetor();
		vetor.alterarTamanho(distancia);

		int MULTIPLICADOR = -1;
		if(ehVertical() || ehHorizontal()) {
			if(getPonto2().yMenorQue(getPonto1())) {
				MULTIPLICADOR = 1;
			} else if(getPonto2().xMenorQue(getPonto1())) {
				MULTIPLICADOR = 1;
			}
		} else {
			if(getPonto1().yMenorQue(getPonto2())) {
				if(getPonto2().xMenorQue(getPonto1())) {
					MULTIPLICADOR = 1;
				}
			} else {
				if(getPonto2().xMenorQue(getPonto1())) {
					MULTIPLICADOR = 1;
				}
			}
		}
		
		vetor.rotacionar(90 * MULTIPLICADOR);
		
		int x1 = (int) (ponto1.getX() + vetor.x);
		int y1 = (int) (ponto1.getY() + vetor.y * -1);
		int x2 = (int) (ponto2.getX() + vetor.x);
		int y2 = (int) (ponto2.getY() + vetor.y * -1);
		Linha linhaMedidaParalela = new Linha(new Ponto(x1, y1), new Ponto(x2, y2));
		linhaMedidaParalela.ehLinhaMedidaParalela = true;
		linhaMedidaParalela.corFundo = Util.getCor("cor_linha_medida_paralela");
		linhaMedidaParalela.criarXs();
		linhaMedidaParalela.rotular();
		return linhaMedidaParalela;
	}

	private void rotular() {
		Vetor vetor = criarVetor();
		long metade = getComprimento() / 2;
		vetor.alterarTamanho((int) metade);
		xRotulo = (int) (ponto1.getX() + vetor.x);
		yRotulo = (int) (ponto1.getY() + vetor.y * -1);
		int comp = (int) (getComprimento() / Constantes.ESCALA_REAL);
		rotulo = "" + comp;
		corFonte = Util.getCor("cor_rotulo_linha_medida_paralela");
	}
	
	private void criarXs() {
		Vetor vetor = criarVetor();
		int tamanhoX = Util.getInt("tamanho_xs_extremos_linha_medida_paralela");
		vetor.alterarTamanho(tamanhoX);
		vetor.rotacionar(45);
		Reta reta = new Reta(ponto1.getX(), ponto1.getY(), (int)(ponto1.getX() + vetor.x), (int)(ponto1.getY() + vetor.y * - 1));
		x1 = new X();
		x1.adicionarFilho(reta);
		vetor.rotacionar(90);
		reta = new Reta(ponto1.getX(), ponto1.getY(), (int)(ponto1.getX() + vetor.x), (int)(ponto1.getY() + vetor.y * - 1));
		x1.adicionarFilho(reta);
		vetor.rotacionar(90);
		reta = new Reta(ponto1.getX(), ponto1.getY(), (int)(ponto1.getX() + vetor.x), (int)(ponto1.getY() + vetor.y * - 1));
		x1.adicionarFilho(reta);
		vetor.rotacionar(90);
		reta = new Reta(ponto1.getX(), ponto1.getY(), (int)(ponto1.getX() + vetor.x), (int)(ponto1.getY() + vetor.y * - 1));
		x1.adicionarFilho(reta);
		
		
		vetor = criarVetor();
		vetor.alterarTamanho(tamanhoX);
		vetor.rotacionar(45);
		reta = new Reta(ponto2.getX(), ponto2.getY(), (int)(ponto2.getX() + vetor.x), (int)(ponto2.getY() + vetor.y * - 1));
		x2 = new X();
		x2.adicionarFilho(reta);
		vetor.rotacionar(90);
		reta = new Reta(ponto2.getX(), ponto2.getY(), (int)(ponto2.getX() + vetor.x), (int)(ponto2.getY() + vetor.y * - 1));
		x2.adicionarFilho(reta);
		vetor.rotacionar(90);
		reta = new Reta(ponto2.getX(), ponto2.getY(), (int)(ponto2.getX() + vetor.x), (int)(ponto2.getY() + vetor.y * - 1));
		x2.adicionarFilho(reta);
		vetor.rotacionar(90);
		reta = new Reta(ponto2.getX(), ponto2.getY(), (int)(ponto2.getX() + vetor.x), (int)(ponto2.getY() + vetor.y * - 1));
		x2.adicionarFilho(reta);
	}
	
	public void normalizarPonto1() {
		Util.normalizar(ponto1);
	}

	public void normalizarPonto2() {
		Util.normalizar(ponto2);
	}

	public Vetor criarVetor() {
		return Util.criarVetor(ponto1, ponto2);
	}

	public long getComprimento() {
		return Math.round(criarVetor().getComprimento());
	}
	
	public boolean estarSob(int x, int y) {
		R2D r = getArea();
		if (!r.contem(x, y)) {
			return false;
		}
		Vetor aux = Util.criarVetor(ponto1.getX(), ponto1.getY(), x, y);
		int compr = (int) aux.getComprimento();
		P2D p = aux.criarP2D();
		Vetor meu = criarVetor();
		meu.alterarTamanho(compr);
		P2D q = meu.criarP2D();
		int distc = p.distancia(q);
		return distc <= ALCANCE_CLICK_LINHA;
	}

	public Linha[] criarSubLinhas(int x, int y) {
		if (getComprimento() < Util.getInt("comprimento_minimo_linha") * 2) {
			Util.mensagem(null, Util.getString("msg_linha_comp_minimo_divisao"));
			return null;
		}

		Vetor aux = Util.criarVetor(ponto1.getX(), ponto1.getY(), x, y);
		int compr = (int) aux.getComprimento();
		Vetor meu = criarVetor();
		meu.alterarTamanho(compr);
		P2D ponta = meu.criarP2D();

		Ponto pontoDivisao = new Ponto(ponto1.getX() + ponta.x, ponto1.getY()
				- ponta.y);

		Linha linha1 = new Linha((Ponto) ponto1.prototipo(), pontoDivisao);
		if (linha1.getComprimento() < Util.getInt("comprimento_minimo_linha")) {
			Util.mensagem(null,
					Util.getString("msg_linha_comp_minimo_divisao_menor"));
			return null;
		}

		Linha linha2 = new Linha((Ponto) pontoDivisao.prototipo(),
				(Ponto) ponto2.prototipo());
		if (linha2.getComprimento() < Util.getInt("comprimento_minimo_linha")) {
			Util.mensagem(null,
					Util.getString("msg_linha_comp_minimo_divisao_menor"));
			return null;
		}

		return new Linha[] { linha1, linha2 };
	}

	public R2D getArea() {
		int x, y, w, a;
		int x1 = ponto1.getX();
		int y1 = ponto1.getY();
		int x2 = ponto2.getX();
		int y2 = ponto2.getY();

		if (x1 == x2 || y1 == y2) {
			int alcance = ALCANCE_CLICK_LINHA;
			int alcanceD = alcance * 2;
			if (x1 == x2) {
				x = x1 - alcance;
				w = alcanceD;
				if (y1 < y2) {
					y = y1;
					a = y2 - y1;
				} else {
					y = y2;
					a = y1 - y2;
				}
				return new R2D(x, y, w, a);
			}
			if (y1 == y2) {
				y = y1 - alcance;
				a = alcanceD;
				if (x1 < x2) {
					x = x1;
					w = x2 - x1;
				} else {
					x = x2;
					w = x1 - x2;
				}
				return new R2D(x, y, w, a);
			}
		}

		if (x1 < x2) {
			x = x1;
			w = x2 - x1;
		} else {
			x = x2;
			w = x1 - x2;
		}

		if (y1 < y2) {
			y = y1;
			a = y2 - y1;
		} else {
			y = y2;
			a = y1 - y2;
		}

		return new R2D(x, y, w, a);
	}

	public void desenhar(Graphics2D g2) {
		if (!isVisivel()) {
			return;
		}
		if(ehLinhaMedidaParalela) {
			g2.setStroke(AbstratoObjeto.LARGURA_LINHA_MEDIDA_PARALELA);
			g2.setColor(corFundo);
			g2.draw(new Line2D.Float(ponto1.getX(), ponto1.getY(), ponto2.getX(), ponto2.getY()));
			x1.desenhar(g2);
			x2.desenhar(g2);
			g2.setColor(corFonte);
			g2.drawString(rotulo, xRotulo, yRotulo);
		} else {
			g2.setStroke(AbstratoObjeto.LARGURA_LINHA);
			if (selecionado) {
				g2.setColor(corSelecionado);
			} else {
				g2.setColor(corFundo);
			}
			g2.draw(new Line2D.Float(ponto1.getX(), ponto1.getY(), ponto2.getX(), ponto2.getY()));
			ponto1.desenhar(g2);
			ponto2.desenhar(g2);
			if(plotado && pontoCentral != null) {
				pontoCentral.desenhar(g2);
			}
		}
	}

	public void setPlotado(boolean plotado) {
		super.setPlotado(plotado);
		ponto1.setPlotado(plotado);
		ponto2.setPlotado(plotado);
	}
	
	public String toString() {
		return "Linha[" + ponto1.toString() + "," + ponto2.toString() + "]";
	}

	public Ponto getPonto1() {
		return ponto1;
	}

	public void setPonto1(Ponto ponto1) {
		this.ponto1 = ponto1;
	}

	public Ponto getPonto2() {
		return ponto2;
	}

	public void setPonto2(Ponto ponto2) {
		this.ponto2 = ponto2;
	}

	public void salvarXML(String prefixo, PrintWriter pw) {
		pw.print(prefixo + "\t<linha ponto1_x='" + ponto1.getX()
				+ "' ponto1_y='" + ponto1.getY() + "' ponto2_x='"
				+ ponto2.getX() + "' ponto2_y='" + ponto2.getY() + "'/>\r\n");
	}

	public void alterarTamanho(int tamanho) {
		//TODO implementar
	}

	public boolean ehIgual(AbstratoObjeto objeto) {
		if(objeto instanceof Linha) {
			Linha linha = (Linha) objeto;
			return ponto1.ehIgual(linha.ponto1) && ponto2.ehIgual(linha.ponto2);
		}
		return false;
	}
	
	public boolean ehVertical() {
		return ponto1.ehIgualX(ponto2);
	}
	
	public boolean ehHorizontal() {
		return ponto1.ehIgualY(ponto2);
	}

	public Ponto getPontoCentral() {
		return pontoCentral;
	}

	public void setPontoCentral(Ponto pontoCentral) {
		this.pontoCentral = pontoCentral;
	}

	public ForcaCentralizada2 getForcaCentralizada2() {
		return forcaCentralizada2;
	}

	public void setForcaCentralizada2(ForcaCentralizada2 forcaCentralizada2) {
		this.forcaCentralizada2 = forcaCentralizada2;
	}
	public double getGrauInclinacao(){
		int x1 = ponto1.getX();
		int y1 = ponto1.getY();
		int x2 = ponto2.getX();
		int y2 = ponto2.getY();	
		if(x1==x2){
			if(y1>y2){
				grauInclinacao = 90;
			}
			if(y1<y2){
				grauInclinacao = 270;
			}
		}else if(y1==y2){
			if(x1<x2){
				grauInclinacao = 0;
			}
			if(x1>x2){
				grauInclinacao = 180;
			}
		}else {
			double n = (double)(y2-y1)/(x2-x1);

			grauInclinacao = Math.toDegrees(Math.atan(n))*(-1);
			
		}
				
		return grauInclinacao;
	}

		
	
	

//	public SetaDinamica getSetaDinamica() {
//		return setaDinamica;
//	}
//
//	public void setSetaDinamica(SetaDinamica setaDinamica) {
//		this.setaDinamica = setaDinamica;
//	}

//	public ForcaCentralizada getForcaCentralizada() {
//		return forcaCentralizada;
//	}
//
//	public void setForcaCentralizada(ForcaCentralizada forcaCentralizada) {
//		this.forcaCentralizada = forcaCentralizada;
//	}
}